<template>
    <el-upload
        ref="uploadRef"
        v-loading="progressFlag"
        list-type="picture-card"
        :accept="upInfo.acceptFile"
        :multiple="multiple"
        :limit="upInfo.limitNum"
        :file-list="uploadFileList"
        :before-upload="beforeAvatarUpload"
        :http-request="uploadRequest"
        :on-exceed="handleExceed"
        element-loading-text="上传中..."
        :class="{ hide: hideUpload }">
        <template #trigger>
            <el-icon class="upload_icon">
                <plus />
            </el-icon>
        </template>
        <template #file="{ file }">
            <div>
                <el-image style="el-upload-list__item-actions" :src="file.url"> </el-image>
                <span class="el-upload-list__item-actions">
                    <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
                        <el-icon><zoom-in /></el-icon>
                    </span>
                    <span class="el-upload-list__item-delete" @click="handleRemove(file)">
                        <el-icon><delete /></el-icon>
                    </span>
                </span>
            </div>
        </template>
        <template #tip>
            <div class="el-upload__tip">
                <span>单张图片大小不超过{{ upInfo.limitSize }}M，支持png；jpg；jpeg格式</span>
            </div>
        </template>
    </el-upload>
    <el-dialog v-model="dialogVisible">
        <img w-full :src="dialogImageUrl" style="width: 100%" alt="Preview Image" />
    </el-dialog>
</template>

<script lang="ts" setup>
import { ref, onUnmounted, onMounted, computed, watch } from 'vue';
import { ElMessage } from 'element-plus';
import type { UploadProps } from 'element-plus';
import type { UploadFile } from 'element-plus/es/components/upload/src/upload';
import { uploadFile2 } from '@/api/common';
import { startLoading, endLoading } from '@/utils/request';
import bus from '@/utils/bus';
import lodash from 'lodash';

/**
 * 上传图片数组
 */
const uploadFileList = ref<UploadFile[]>([]);

/**
 * 是否为编辑
 */
const isEdit = ref(false);

/**
 * 是否上传完成
 */
const progressFlag = ref(false);

const dialogVisible = ref(false);

const dialogImageUrl = ref('');

/**
 * 文件上传组件实例
 */
const uploadRef = ref(null);

// 是否已上传
const isStop = ref(false);

// 上传之前的校验图片
const beforeUploadFlag = ref<boolean>(true);

// 当前选择的文件列表
const selectFileList = ref<any[]>([]);

const props = defineProps<{
    upInfo: {
        type: number; //文件类型
        label: string; //文件名称
        prop: string; // 是否是必传
        files: any; //文件
        multiple: {
            //是否支持多选
            type: boolean;
            default: false;
        };
        limitSize: number; // 最大文件上传限制
        limitNum: {
            // 上最大传数量
            type: number;
            default: 1;
        };
        acceptFile: string; // 上传类型文件判断
    };
}>();

const multiple = ref(props.upInfo.multiple); // 是否多选

const emit = defineEmits(['submit']);

/**
 * 当文件选择的数量超出限制时，执行的钩子函数
 */
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
    ElMessage.warning(
        `当前限制选择 ${props.upInfo.limitNum} 个文件，本次选择了${files.length}  个文件，共选择了${
            files.length + uploadFiles.length
        } 个文件`
    );
};

const hideUpload = computed(() => {
    return uploadFileList.value.length >= (isEdit.value ? 1 : props.upInfo.limitNum);
});
/**
 * @description: 文件上传前的回调
 * @return {*}
 */
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
    const currentFileList = lodash.cloneDeep(uploadFileList.value);
    if (beforeUploadFlag.value) {
        const ext = rawFile.name.substring(rawFile.name.lastIndexOf('.'));
        if (props.upInfo.acceptFile.indexOf(ext) == -1) {
            ElMessage.warning(`上传图片是${ext}格式,请上传${props.upInfo.acceptFile}格式图片`);
            beforeUploadFlag.value = false;
            uploadRef.value?.clearFiles();
            uploadRef.value?.abort();
            uploadFileList.value = currentFileList;
            return false;
        } else if (rawFile.size / 1024 / 1024 > props.upInfo.limitSize) {
            ElMessage.error(`上传图片单张最大支持 ${props.upInfo.limitSize}MB!`);
            beforeUploadFlag.value = false;
            uploadRef.value?.clearFiles();
            uploadRef.value?.abort();
            uploadFileList.value = currentFileList;
            return false;
        }
        selectFileList.value.push(rawFile);
        beforeUploadFlag.value = true;
        return true;
    } else {
        uploadRef.value?.clearFiles();
        uploadRef.value?.abort();
        uploadFileList.value = currentFileList;
        return false;
    }
};

/**
 * 自定义上传方法
 */
const uploadRequest = (params: any) => {
    if (isStop.value) {
        return false;
    }
    isStop.value = true;
    if (beforeUploadFlag.value) {
        startLoading();
        const currentFileList = lodash.cloneDeep(uploadFileList.value);
        Promise.all(
            selectFileList.value.map(async file => {
                return await new Promise((resolve, reject) => {
                    uploadFile2(
                        {
                            file,
                            fileName: file.name
                        },
                        { noNeedLoading: true },
                        60000 * 2
                    )
                        .then(res => {
                            resolve(res);
                        })
                        .catch(err => {
                            // uploadRef.value?.clearFiles();
                        });
                });
            })
        )
            .then(list => {
                uploadFileList.value.push(...list);
                emit('submit', uploadFileList.value, false);
            })
            .catch(err => {
                beforeUploadFlag.value = false;
                uploadRef.value?.clearFiles();
                uploadRef.value?.abort();
                uploadFileList.value = currentFileList;
            })
            .finally(() => {
                isStop.value = false;
                selectFileList.value.splice(0);
                endLoading();
            });
    }
};

const handleRemove = (file: any) => {
    uploadRef.value?.handleRemove(file);
    uploadFileList.value = uploadFileList.value.filter(item => item.name != file.name);
    emit('submit', uploadFileList.value, true);
};

/**
 * 清空数据回显
 */
const empty = () => {
    uploadFileList.value = [];
};

/**
 * 编辑状态时只能上传一张照片
 */
const singleImg = (res: boolean) => {
    isEdit.value = res;
};

/**
 * 编辑时图片回显
 */

const echo = (data: any) => {
    isEdit.value = true;
    const type = props.upInfo.type;
    if (type == 1) {
        if (data.cover_image_url) {
            uploadFileList.value.push({
                url: data.cover_image_url,
                name: '',
                status: 'ready',
                uid: 0
            });
        } else {
            data.forEach((item: any) => {
                return uploadFileList.value.push({
                    url: item.absolute_url,
                    name: '',
                    status: 'ready',
                    uid: 0
                });
            });
        }
    } else if (type == 4) {
        uploadFileList.value.push({
            name: data.title,
            url: undefined,
            status: 'ready',
            uid: 0
        });
    }
    return;
};

const handlePictureCardPreview = (file: UploadFile) => {
    dialogImageUrl.value = file.url!;
    dialogVisible.value = true;
};

const initUpload = () => {
    const dom = document.querySelector('.el-upload.el-upload--picture-card');
    dom?.addEventListener('click', () => {
        beforeUploadFlag.value = true;
    });
};

/**
 * 上传图片的弹框
 */
const upPic = () => {
    isEdit.value = false;
};
bus.on('upPic', upPic);

defineExpose({ empty, echo, singleImg, upPic });

/**
 * 编辑图片时，只能编辑单张图片，所以把是否多选置为 false
 */
watch(
    () => isEdit.value,
    val => {
        if (val) {
            multiple.value = false;
        } else {
            multiple.value = props.upInfo.multiple;
        }
    }
);

onMounted(() => {
    initUpload();
});
onUnmounted(() => {
    bus.off('upPic', upPic);
});
</script>

<style scoped>
.avatar-uploader .avatar {
    width: 178px;
    height: 178px;
    display: block;
}
</style>

<style lang="scss" scoped>
.pre_img_box {
    overflow: hidden;
    .pre_image {
        display: block;
        margin: auto;
        max-height: 400px;
    }
}
.hide :deep(.el-upload--picture-card) {
    display: none;
}
.upload_icon {
    width: 140px;
    height: 90px;
}
</style>
